/**
  reactive：
    接受一个参数，判断这参数是否是对象，如果不是直接返回
    创建拦截器对象handler，设置get/set/delete/Property
    返回Proxy对象
  

  ref与reactive区别：
    ref可以把基本数据类型数据，转换成响应式对象，而reactive不可以
    ref返回的对象，重新赋值成对象也是响应式的
    reactive返回的对象，重新赋值丢失响应式
    reactive返回的对象不可解构
 */



let isObject = value => value !== null && typeof value === 'object'
let convert = target => isObject(target) ? reactive(target) : target  //递归绑定getter/setter
let hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) => hasOwnProperty.call(target ,key)
export function reactive(target) {
  if(!isObject(target)) return target

  const handler = {
    get(target, key, receiver) {
      //收集依赖
      track(target, key)
      // console.log('get', key);
      const result = Reflect.get(target, key, receiver)
      return convert(result)
    },
    set(target, key, value, receiver) {
       const oldValue = Reflect.get(target, key, receiver)
       let result = true
       if(oldValue !== value) {
        result = Reflect.set(target, key, value, receiver)
         //触发更新
         trigger(target, key)
        //  console.log('set', key, value);
       }
       return result
    },
    deleteProperty(target, key) {
       const hadKey = hasOwn(target, key)
       const result = Reflect.deleteProperty(target, key)
       if(hadKey && result) {
         //触发更新
         trigger(target, key)
        //  console.log('delete', key);
       }
       return result
    }
  }

  return new Proxy(target, handler)
}



/**
 * 收集依赖
 * @param {*} callback  Fn
 * 
 */

 let activeEffect = null;
export function effect(callback) {
  activeEffect = callback
  callback()  //访问响应式对象属性，去收集依赖
  activeEffect = null;
}



//可查看手机依赖图、images/手机依赖图.png
let targetMap = new WeakMap()
export function track(target, key) {
  if(!activeEffect) return 
  let depsMap = targetMap.get(target)
  if(!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key)
  if(!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  dep.add(activeEffect)
}


/**
 * 触发更新
 */

 export function trigger(target ,key) {
   const depsMap = targetMap.get(target)
   if(!depsMap) return
   const dep = depsMap.get(key)
   if(dep) {
     dep.forEach(effect => {
       effect()
     })
   }
 }


 export function ref(raw) {
   //判断raw是否是ref创建的对象，如果是的话直接返回
   if(isObject(raw) && raw.__v_isRef) return
   let value = convert(raw)
   let r = {
     __v_isRef: true,
     get value () {
         track(r, 'value')
         return value
     },
     set value(newValue) {
       if(newValue !== value) {
         raw = newValue
         value = convert(raw)
         trigger(r, 'value')
       }
     }
   }
   return r
 }


 /**
  * 接受reactive返回的响应式对象,然后将传入对象的所有属性转成类似ref的新对象，然后返回
  */
 export function toRefs(proxy) {
   const ret = proxy instanceof Array ? new Array(proxy.length) : {}
   for(const key in proxy) {
    ret[key] = toProxyRef(proxy, key)
   }
   return ret
 }

//将
 function toProxyRef(proxy, key) {
   const r = {
     __v_isRef: true,
     get value() {
       return proxy[key]
     },
     set value(newValue) {
       proxy[key] = newValue
     }
   }
   return r
 }


 /**
  * 
  * @param {*} getter 获取结果的函数
  * 
  * 接收一个有返回值的函数作为参数，函数的值就是计算属性的值，返回一个ref创建的对象
  */
 export function computed(getter) {
   const result = ref() //不传参数，默认返回undefined
   effect(() => (result.value = getter()))
   return result
 }